const os = require("os");
// commonjs 模块
const ESLintPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const path = require("path");
const TerserWebpackPlugin = require("terser-webpack-plugin");
const threads = os.cpus().length || 1; // cpu 数量

module.exports = {
  // 入口
  entry: "./src/main.js",
  // 输出
  output: {
    // 开发模式没有输出
    path: undefined,
    // 入口文件打包输出文件名
    filename: "js/[name].js",
    // 给打包输出的其他文件名
    chunkFilename: "static/js/[name].chunk.js",
    
    // hash 唯一标识 ext：原有文件扩展名
    // 图片、字体等通过 type:asset 处理的资源命名
    assetModuleFilename:'static/image/[hash:5][ext][query]',
  },
  // 加载器
  module: {
    rules: [
      // loader 配置
      {
        oneOf: [ // 只匹配第一个满足的loader
          {
            test: /\.css$/i, // 只检测.css文件
            use: [
              MiniCssExtractPlugin.loader,
              //  执行顺序：从右到左，从下到上
              // "style-loader", // 将js中的css通过创建style标签添加到html文件中生效
              "css-loader",  //  将css资源编译成 commomjs 的模块到js中
            ]
          },
          {
            test: /\.less$/i,
            use: [
              // compiles Less to CSS
              'style-loader',
              'css-loader',
              'less-loader',
            ],
          },
          {
            test: /\.s[ac]ss$/i,
            use: [
              'style-loader',
              'css-loader',
              'sass-loader',
            ],
          },
          {
            test: /\.styl$/,
            use: [
              'style-loader',
              'css-loader',
              "stylus-loader"
            ], // 将 Stylus 文件编译为 CSS
          },
          {
            test: /\.(png|jpe?g|svg|webp)$/,
            type: "asset",
            parser: {
              dataUrlCondition: {
                // 小于19kb 的图片转base64
                // base64优点：减少请求数量，缺点：体积会增大1/3
                maxSize: 19 * 1024, // 4kb,视为 inline 模块｜resource 模块的界限
              }
            },
            // Rule.generator.filename 与 output.assetModuleFilename 相同，并且仅适用于 asset 和 asset/resource 模块类型。
            // generator: {
            //   filename: 'static/image/[hash][ext][query]'
            // }
          },
          {
            // 资源 resource 输出
            test: /\.(ttf|woff2?|mp3|avi)$/,
            type: "asset/resource",
            // generator: {
            //   filename: 'static/media/[hash:10][ext][query]'
            // }
          },
          {
            test: /\.m?js$/,
            exclude: /(node_modules|bower_components)/,  // 排除
            include: path.resolve(__dirname,'../src'), // 只处理src下的文件
            use: [
              {
                loader: 'thread-loader',
                options: {
                  workers: threads - 1, // 开启多进程和进程数量
                }
              },
              {
                loader: 'babel-loader',
                options: {
                  // presets: ['@babel/preset-env']
                  cacheDirectory: true, // 开启 babel 缓存
                  cacheCompression: false, // 关闭缓存文件压缩
                  plugins: ['@babel/plugin-transform-runtime']  //禁用了 Babel 自动对每个文件的 runtime 注入，减少代码体积
                }
              }
            ]
          }
        ],
      },
    ]
  },
  // 插件
  plugins: [
    new HtmlWebpackPlugin({
      // 模版：以public/index.html 文件创建新的html文件
      // 新的html文件的特点：1. 结构与原来一致，2. 自动引入打包输出的资源
      template: path.resolve(__dirname, "../public/index.html")
    }),
    new ESLintPlugin({
      // 检测哪些文件
      context: path.resolve(__dirname, "../src"),
      exclude: "node_module",
      cache: true,
      cacheLocation: path.resolve(__dirname, "../node_modules/.cache/eslintcache")
    }),
    new MiniCssExtractPlugin(),
    new TerserWebpackPlugin({
      parallel: threads
    })
  ],
  // 模式
  mode: "development",
  // 开发服务器：不会输出资源，在内存中编译打包
  devServer: {
    host: "localhost",
    port: "3000",
    open: true,
    hot: true, // HMR 热模块替换
  },
  // 只映射行关系，没有列映射
  devtool: "cheap-module-source-map",
}